package cn.bone.auth.security.base.conf;

import cn.bone.auth.security.service.impl.UserDetailsServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import javax.annotation.Resource;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource(name = "userDetailsServiceImpl")
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider(){
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        //不隐藏用户未找到
        daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
        daoAuthenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        return daoAuthenticationProvider;
    }


    //认证用户的来源[内存或数据库]
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

/*        //在配置类中指定角色,不能加前缀 ROLE_
        auth.inMemoryAuthentication()
                .withUser("user").password("{noop}123456").roles("USER","ORDER")
                .and()
                .withUser("admin").password("{noop}123456").roles("ADMIN","USER");*/

//        //使用自定义的用户认证授权
//        //使用默认的密码加密处理
//        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());

        //不隐藏用户未找到异常
        auth.authenticationProvider(daoAuthenticationProvider());

    }




    //配置SpringSecurity相关信息
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //释放静态资源,指定资源拦截规则,指定之定义认证页面,指定退出认证配置 CSRF配置
        http.authorizeRequests()
                //不拦截的资源
                .antMatchers("/loginPage",
                        "/fail",
                        "/css/**",
                        "/js/**",
                        "/images/**",
                        "/favicon.ico").permitAll()
                //需要权限认证的资源
                .antMatchers("/**").hasAnyRole("USER","ADMIN")
                //其他的资源需要登录认证才能访问
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/loginPage")
                .usernameParameter("myName")
                .passwordParameter("myPass")
                .loginProcessingUrl("/login")
                .defaultSuccessUrl("/index")

                //自定义错误处理
//                .failureUrl("/fail")
                .failureHandler(((request, response, e) -> {
                    System.out.println("exceptionType: " + e.getClass());
                    System.out.println("exceptionMessage: " + e.getMessage());

                    //用户不存在
                    if(e instanceof InternalAuthenticationServiceException){
                        System.out.println("登录认证错误: 用户不存在");
                    }
                    //密码错误
                    else if(e instanceof BadCredentialsException){
                        System.out.println("登录认证错误: 密码错误");
                    }

                    response.sendRedirect("/fail");
                }))

                .permitAll()
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/loginPage")
//                .invalidateHttpSession(true)
                .permitAll()
                .and()
                .csrf()
                .disable();
    }


}
